module MyLib (someFunc) where
import Control.Concurrent 
import Codec.FFmpeg
import Codec.Picture
import Control.Concurrent.STM
import Control.Concurrent.STM.TQueue
import Control.Concurrent.STM.TBQueue
import Control.Concurrent.STM.TMVar (newEmptyTMVar,takeTMVar,putTMVar)
import Control.Monad
import System.Exit(exitSuccess)
import System.IO 
import qualified Data.Vector.Storable as V
import Foreign
import Foreign.C

import qualified Foreign.Concurrent as FC


-- import qualified Foreign.ForeignPtr as FF 


foreign import ccall "wrapper" createFun1 :: (Ptr a->IO()) -> IO ( FunPtr (Ptr a->IO ()) )




sleepMs:: Int->IO ()
sleepMs n=threadDelay (n* 1000000)

-- myincrease::TMVar Int->STM ()
--myincrease count=do 

-- jiance_zhongzhi::TMVar Int->TVar Int-> IO()
-- 




-- forkIO $ forever $ do 
--         value<- atomically $ readTVar count
--         if value>50 then do 
--             value1<-atomically $ takeTMVar signal1
--             sleepMs 3
--             atomically $ putTMVar signal1 1
--         else 
--             return ()


fill_video_frame2queue::TMVar Int-> TVar Int->IO (Maybe (Image PixelRGB8,Double))->TQueue (Image PixelRGB8,Double)->IO ()
fill_video_frame2queue signal count getFrame tqueue= do 
    value <-atomically $ takeTMVar signal
    fra<- getFrame    
    atomically $  putTMVar signal 1
    vv<- myfun fra tqueue count
    if vv>0 then 
        fill_video_frame2queue signal count getFrame tqueue
    else do 
        putStrLn "end fill_video_frame2queue"
        return ()
    where 
        myfun ::Maybe (Image PixelRGB8,Double)->TQueue (Image PixelRGB8,Double)->TVar Int->IO Int
        myfun Nothing _  _ = return (-1)
        myfun (Just x) tqueue1 count1= do 
            value1<- atomically $ readTVar count1
            putStrLn $ "fill one tqueue " ++ (show value1) ++ "  " ++(show $ snd x )
            atomically $ modifyTVar count1 (\x->x+1) 
            --atomically $ writeTVar count1 (value1+1)
            atomically $ writeTQueue tqueue1  x 
            return 1


-- fib = 0:1:zipWith (+) fib (tail fib) 

control_frame::TMVar Int->TVar Int ->IO ()
control_frame signal count=do 
    value<- atomically $ readTVar count
    if value>50 then do 
        value1<-atomically $ takeTMVar signal
            -- sleepMs 5
        putStrLn "pause" 
        myfun signal count 
      
    else 
        return ()

    control_frame signal count
    where 
        myfun :: TMVar Int->TVar Int->IO ()
        myfun signal1 count1=do 
            value2<- atomically $ readTVar count1
            if value2 <=50 then do 
                putStrLn $ "end pause" ++ ( show value2)
                atomically $ putTMVar signal1 1
            else do 
                putStrLn $ "pause " ++ (show value2)
                myfun signal1 count1



write_video_frame_from_queue::TMVar Int->TVar Int -> TQueue (Image PixelRGB8,Double)->IO ()
write_video_frame_from_queue signal count tqueue=do
    is<- myfun tqueue
    if is then do 
        putStrLn "end writeBitmap"
        return ()
    else do 
        value<-atomically $ takeTMVar signal
        atomically $ putTMVar signal 1    
        im<-atomically  $ readTQueue tqueue 
        value1<- atomically $ readTVar count

        putStrLn $ "write one bmp" ++ (show value1)
        --atomically $ writeTVar count (value1 -1)
        atomically $ modifyTVar count (\x->x-1)
        writeBitmap "test.bmp"  $ fst im
        write_video_frame_from_queue signal count  tqueue 
    where
        myfun ::TQueue a->IO Bool
        myfun tqueue1=do 
            is1<- atomically $ isEmptyTQueue tqueue1
            if is1 then do 
                sleepMs 1
                atomically $ isEmptyTQueue tqueue1
            else do 
                return is1  

           
-- Storable a => Vector a -> (ForeignPtr a, Int) 
-- unsafeToForeignPtr0
-- vector foldl foldlM
--
-- foldlM:: (a->a->m a)->Vector a-> m a
-- foldM:: (a->b->m a)->a ->Vector b ->m a
--
-- unsafeWith


-- mallocBytes $ 

mynewForeignPtr:: Ptr a->IO (ForeignPtr a)
mynewForeignPtr  ptr= FC.newForeignPtr ptr $ free ptr 



-- convert_image2Foreignptr::Image PixelRGB8->(ForeignPtr ( PixelBaseComponent PixelRGB8),Int) 
-- convert_image2Foreignptr im= V.unsafeToForeignPtr0 $ imageData im 


-- FF.newForeignPtr_:: Ptr a-> IO (ForeignPtr a)
-- V.unsafeFromForeignPtr0 :: ForeignPtr a ->Int ->Vector a 




convert_vector2ptr:: V.Vector (PixelBaseComponent PixelRGB8)-> IO (Ptr CUChar)
convert_vector2ptr v= V.unsafeWith v myfun 
    where
        len1=V.length v
        myfun :: Ptr (PixelBaseComponent PixelRGB8)->IO (Ptr CUChar)
        myfun ptr =do 
            ptr1<- mallocBytes len1
            copyBytes ptr1 (castPtr ptr ::Ptr CUChar) len1
            return ptr1



convert_ptr2vector:: Storable a=> Ptr a->Int->IO (V.Vector a )

convert_ptr2vector ptr1 size1
    | ptr1==nullPtr = return V.empty
    | otherwise =do
        ptr2<-mynewForeignPtr ptr1
    -- size2<-return.sizeOf =<< peek ptr1
        return $ V.unsafeFromForeignPtr0 ptr2 size1
 
myconvert_ptr2vector::Storable a=>Ptr a->Int ->IO (V.Vector a)
myconvert_ptr2vector ptr1 size1
    | ptr1== nullPtr= return V.empty
    | otherwise =do 
        size2<- return .sizeOf =<<peek ptr1
        ptr2<- mallocBytes (size2*size1)
        copyBytes ptr2 ptr1 (size1*size2)
        convert_ptr2vector ptr2 size1  
        -- where 
        --     size2= re

    -- do 
    -- ptr2<-mallocBytes (size1*)
    -- where 
    --     size2=sizeOf 



myconvertimage2ptr::Image PixelRGB8 ->IO (Ptr CUChar)
myconvertimage2ptr im= do 
    ptr<- mallocBytes (imageWidth im * imageHeight im *3) 
    -- V.foldM myfun (imageData) 
    -- pokeByteOff 
    -- ((imageData im ) V.! 0)  
    return ptr
    where 
        size1=sizeOf (1::CUChar)
        myfun :: (Ptr CUChar,Int)->V.Vector (PixelBaseComponent PixelRGB8)->IO (Ptr CUChar,Int)
        myfun  (ptr1,len1) v1 = do 
            pokeByteOff ptr1 (len1*3*size1) (v1 V.! len1)
            return (ptr1,len1+1)


        -- myfun1::PixelBaseComponent Int ->IO ()
        -- myfun1 x=putStrLn $ show x
        -- myfun1:: PixelBaseComponent PixelRGB8->IO ()
        -- myfun1 ((PixelRGB8 r g b))=do 
        --     putStrLn $ show r


-- test1::TMVar Int-> IO()
-- test1 s = do
--     putStrLn "begin" 
--     sleepMs 6
--     atomically  $ putTMVar s 2
--     putStrLn "end"
someFunc1:: IO ()
someFunc1 =do 

    -- putStrLn $ show $ sizeOf (undefined::CUChar) 
    myfunptr <- createFun1 free 
    myptr<-mallocBytes 100

    myptr1<- FC.newForeignPtr myptr $ do
        free myptr  
        putStrLn "end finisher" 
    -- myptr1<- FC.newForeignPtr myfunptr myptr 
    -- myptr1<- FF.newForeignPtr_ myptr

    -- free myptr
    myptr2<-mallocBytes $ sizeOf (1::Float)*2 :: IO (Ptr Float )
    pokeByteOff myptr2 0 (99::Float )
    pokeByteOff myptr2 (sizeOf (1::Float)) (88::Float )

    vec2<- convert_ptr2vector myptr2 2
    putStrLn $ "length :" ++ (show $ V.length vec2)

    im1<-readImage ("test1.bmp")
    im<-return $ convertRGB8 $ (\(Right x)->x) im1
    putStrLn $ show $ imageWidth im
    putStrLn $ show $ imageHeight im 

    putStrLn "someFunc1"




someFunc :: IO ()
someFunc = do 

    someFunc1 

    tqueue<- atomically $  newTQueue
    signal1<- atomically $ newTMVar 1 
    signal2<- atomically $ newTMVar 2
    count<- atomically $ newTVar 0 
    --myptr<-V.unsafeWith (imageData im)  (\x->return x)
    -- free myptr 
    -- imageData im 
    --putStrLn $ show $ snd $ convert_image2ptr im
    -- sleepMs 20
    putStrLn "here"
    initFFmpeg
    (getFrame,cleanup)<- imageReaderTime (File "demo.mp4"):: IO (IO (Maybe (Image PixelRGB8,Double)),IO() )
    -- te<- return 1
    -- l<- return True
    -- if l then do
    --     te<- return 3
    --     return ()
    -- else do 
    --     te<- return 5
    --     return ()
    -- putStrLn$  show te 
    -- tbqueue<- atomically $  newTBQueue 2
    -- atomically $ writeTBQueue tbqueue 1
    -- atomically $ readTBQueue tbqueue
    -- len1<- atomically $ lengthTBQueue tbqueue
    -- putStrLn $ "fdsd " ++ ( show len1) 
    forkIO $ fill_video_frame2queue signal1 count  getFrame tqueue 
    putStrLn "herere"
    forkIO $ control_frame signal1 count  


    write_video_frame_from_queue signal2 count tqueue

    putStrLn $ show $ sizeOf (1::PixelBaseComponent PixelRGB8)
    -- (getFrame,cleanup)<- imageReaderTime ()
    -- im<-atomically $ readTQueue tqueue  
    -- putStrLn "newTMVar "
    -- signal <- atomically $ newTMVar 1
    -- putStrLn "takeTMVar"
    -- value<- atomically $ takeTMVar signal
    -- forkIO $ test1 signal
    -- putStrLn "takeTMVar"
    -- value<- atomically $ takeTMVar signal 
    putStrLn "someFunc"
